package com.clp.protocol.iec104.iec104.client.state;

import com.clp.protocol.core.async.NSuccessPolicy;
import com.clp.protocol.core.common.ActivateControl;
import com.clp.protocol.iec104.iec104.apdu.Apdu;
import com.clp.protocol.iec104.iec104.client.InMaster;
import com.clp.protocol.iec104.iec104.client.config.MasterConfig;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.Promise;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ScheduledExecutorService;
import java.util.stream.Collectors;

/**
 * 主站状态管理：提供主站状态信息的查询、指定状态的获取
 */
@Slf4j
public class InMasterStateManager implements MasterStateInfo, ActivatableState<Future<Void>> {
    @Getter
    private final InMaster inMaster;
    private final LinkedList<MasterState> masterStates = new LinkedList<>();

    public InMasterStateManager(InMaster inMaster, MasterConfig cfg) {
        this.inMaster = inMaster;

        addState(new T0T1T2T3MasterState(this, cfg.getT0(), cfg.getT1(), cfg.getT2(), cfg.getT3()));
        addState(new DtMasterState(this, cfg.isAutoStartDtV(), 3));
        addState(new RecvInitEndMasterState(this));
        addState(new TotalCall100MasterState(this, cfg.getTotalCall100PeriodSeconds()));
        addState(new TotalCall101MasterState(this, cfg.getTotalCall101PeriodSeconds()));
        addState(new TcMasterState(this));
        addState(new TaMasterState(this));
    }

    /**
     * 添加主站状态
     * @param masterState
     */
    private void addState(MasterState masterState) {
        masterStates.addLast(masterState);
    }

    @SuppressWarnings("unchecked")
    public <T extends MasterState> T getState(Class<T> stateClass) {
        for (MasterState state : masterStates) {
            if (state.getClass() == stateClass) {
                return ((T) state);
            }
        }
        throw new RuntimeException("找不到对应的状态类：" + stateClass.getName());
    }

    protected ScheduledExecutorService scheduledExecutorService() {
        return inMaster.getAsyncSupport().scheduledExecutorService();
    }

    protected  <T> Promise<T> createPromise(Class<T> clazz) {
        return inMaster.getAsyncSupport().createPromise(clazz);
    }

    @Override
    public Future<Void> activate() {
        Promise<Void> promise = createPromise(Void.class);
        List<MasterState> activatedStates = new Vector<>();
        List<Future<Void>> childFutures = masterStates.stream().map(state -> state.activate().addListener(new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                if (future.isSuccess()) {
                    activatedStates.add(state);
                }
            }
        })).collect(Collectors.toList());
        NSuccessPolicy.ALL_IS_SUCCESS.apply2(promise, childFutures);
        promise.addListener(new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                if (!future.isSuccess()) {
                    log.warn("[StateManager] 状态激活失败！");
                    activatedStates.forEach(ActivateControl::inactivate);
                }
            }
        });
        return promise;
    }

    @Override
    public boolean isActivated() {
        for (MasterState state : masterStates) {
            if (!state.isActivated()) {
                return false;
            }
        }
        return true;
    }

    @Override
    public Future<Void> reactivate() {
        Promise<Void> promise = createPromise(Void.class);
        List<MasterState> reactivatedStates = new Vector<>();
        List<Future<Void>> childFutures = masterStates.stream().map(state -> state.reactivate().addListener(new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                if (future.isSuccess()) {
                    reactivatedStates.add(state);
                }
            }
        })).collect(Collectors.toList());
        NSuccessPolicy.ALL_IS_SUCCESS.apply2(promise, childFutures);
        promise.addListener(new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                if (!future.isSuccess()) {
                    log.warn("[StateManager] 状态重新激活失败！");
                    reactivatedStates.forEach(ActivateControl::inactivate);
                }
            }
        });
        return promise;
    }

    @Override
    public Future<Void> inactivate() {
        Promise<Void> promise = createPromise(Void.class);
        List<Future<Void>> childFutures = masterStates.stream().map(ActivateControl::inactivate).collect(Collectors.toList());
        NSuccessPolicy.ALL_IS_SUCCESS.apply2(promise, childFutures);
        return promise;
    }

    @Override
    public Apdu updateStateBySending(Apdu apdu) {
        for (int i = masterStates.size() - 1; i >= 0 ; i--) {
            apdu = masterStates.get(i).updateStateBySending(apdu);
        }
        return apdu;
    }

    @Override
    public Apdu updateStateByRecving(Apdu apdu) {
        for (MasterState state : masterStates) {
            apdu = state.updateStateByRecving(apdu);
        }
        return apdu;
    }

    @Override
    public int totalCall100PeriodSeconds() {
        return 0;
    }

    @Override
    public int totalCall101PeriodSeconds() {
        return 0;
    }

    @Override
    public int t0Seconds() {
        return 0;
    }

    @Override
    public int t1Seconds() {
        return 0;
    }

    @Override
    public int t2Seconds() {
        return 0;
    }

    @Override
    public int t3Seconds() {
        return 0;
    }

    @Override
    public boolean isStartedDt() {
        return getState(DtMasterState.class).isStartedDt();
    }

    @Override
    public boolean isRecvedInitEnd() {
        return getState(RecvInitEndMasterState.class).isRecvedInitEnd();
    }

    @Override
    public boolean isTestingFr() {
        return getState(T0T1T2T3MasterState.class).isTestingFr();
    }

    @Override
    public boolean isDoingTotalCall100() {
        return getState(TotalCall100MasterState.class).isDoingTotalCall100();
    }

    @Override
    public boolean isDoingTotalCall101() {
        return getState(TotalCall101MasterState.class).isDoingTotalCall101();
    }

    @Override
    public List<Integer> listAllDoingTcAddrs() {
        return getState(TcMasterState.class).listAllDoingTcAddrs();
    }

    @Override
    public List<TcMasterState.PtState> listAllDoingTcPtStates() {
        return getState(TcMasterState.class).listAllDoingTcPtStates();
    }

    @Override
    public boolean isDoingOnePointTcSelect(int infoObjAddr) {
        return getState(TcMasterState.class).isDoingOnePointTcSelect(infoObjAddr);
    }

    @Override
    public boolean isDoingTwoPointTcSelect(int infoObjAddr) {
        return getState(TcMasterState.class).isDoingTwoPointTcSelect(infoObjAddr);
    }

    @Override
    public boolean isDoingOnePointTcExecute(int infoObjAddr) {
        return getState(TcMasterState.class).isDoingOnePointTcExecute(infoObjAddr);
    }

    @Override
    public boolean isDoingTwoPointTcExecute(int infoObjAddr) {
        return getState(TcMasterState.class).isDoingTwoPointTcExecute(infoObjAddr);
    }

    @Override
    public List<TaMasterState.PtState> listAllDoingTaPtStates() {
        return getState(TaMasterState.class).listAllDoingTaPtStates();
    }

    @Override
    public boolean isDoingTaSelectNormalized(int infoObjAddr) {
        return getState(TaMasterState.class).isDoingTaSelectNormalized(infoObjAddr);
    }

    @Override
    public boolean isDoingTaSelectScaled(int infoObjAddr) {
        return getState(TaMasterState.class).isDoingTaSelectScaled(infoObjAddr);
    }

    @Override
    public boolean isDoingTaSelectFloat(int infoObjAddr) {
        return getState(TaMasterState.class).isDoingTaSelectFloat(infoObjAddr);
    }

    @Override
    public boolean isDoingTaExecuteNormalized(int infoObjAddr) {
        return getState(TaMasterState.class).isDoingTaExecuteNormalized(infoObjAddr);
    }

    @Override
    public boolean isDoingTaExecuteScaled(int infoObjAddr) {
        return getState(TaMasterState.class).isDoingTaExecuteScaled(infoObjAddr);
    }

    @Override
    public boolean isDoingTaExecuteFloat(int infoObjAddr) {
        return getState(TaMasterState.class).isDoingTaExecuteFloat(infoObjAddr);
    }
}
